package com.zjw.zy.common;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.*;


/**
 * @author zhongjiwei
 * @eMail: 975836251@qq.com
 */
public final class JsonUtils {

    private JsonUtils() {
        throw new UnsupportedOperationException("try to instance utils.");
    }


    /**
     * bean 转换 json字
     */
    public static String toJson(Object obj) {
        if (obj == null) {
            return EMPTY;
        }
        return toJsonInner(obj);
    }

    /**
     * * map 转换 json字
     */
    public static String toJson(Map<?, ?> map) {
        if (map == null) {
            return EMPTY;
        }
        return forMap(map);
    }

    /**
     * json 转换 bean
     */
    public static <T> T fromJson(String json, Class<T> clazz) {
        if (json == null || json.isEmpty() || json.equals(EMPTY)) {
            return null;
        }
        return fromJsonInner(json, clazz);
    }

    /**
     * json 转换 Map
     */
    public static <K, V> Map<K, V> toMap(String json, Class<K> keyClass, Class<V> valueClass) {
        if (json == null || json.isEmpty() || json.equals(EMPTY)) {
            return Collections.emptyMap();
        }
        return parseMapObject(json, HashMap.class, keyClass, valueClass);
    }

    /**
     * json 格式化
     */
    public static String formatJsonString(String json) {
        if (json == null || json.isEmpty() || json.equals(EMPTY)) {
            return EMPTY;
        }
        return formatJsonStringInner(json);
    }

    /**
     * json 反格式化
     */
    public static String unFormatJsonString(String json) {
        if (json == null || json.isEmpty() || json.equals(EMPTY)) {
            return EMPTY;
        }
        return unFormatJsonStringInner(json);
    }


    /**
     * ======================================== 内部实现 ================================================================
     */


    private static final char LEFT = '{';
    private static final char RIGHT = '}';
    private static final char ARRAY_LEFT = '[';
    private static final char ARRAY_RIGHT = ']';
    private static final char TYPE_LEFT = '<';
    private static final char TYPE_RIGHT = '>';
    private static final char POINT = ',';
    private static final char MAO_POINT = ':';
    private static final String EMPTY = "\"\"";


    private static final Set<String> sBasicClass = new HashSet<>();


    /**
     * ======================================java基本类型常量============================================================
     */
    private static final String JAVA_LANG_INTEGER = "java.lang.Integer";
    private static final String JAVA_LANG_BYTE = "java.lang.Byte";
    private static final String JAVA_LANG_SHORT = "java.lang.Short";
    private static final String JAVA_LANG_LONG = "java.lang.Long";
    private static final String JAVA_LANG_FLOAT = "java.lang.Float";
    private static final String JAVA_LANG_DOUBLE = "java.lang.Double";
    private static final String JAVA_LANG_BOOLEAN = "java.lang.Boolean";
    private static final String JAVA_LANG_STRING = "java.lang.String";
    private static final String JAVA_LANG_CHARACTER = "java.lang.Character";
    private static final String JAVA_INTEGER = "int";
    private static final String JAVA_BYTE = "byte";
    private static final String JAVA_SHORT = "short";
    private static final String JAVA_LONG = "long";
    private static final String JAVA_FLOAT = "float";
    private static final String JAVA_DOUBLE = "double";
    private static final String JAVA_BOOLEAN = "boolean";
    private static final String JAVA_CHARACTER = "character";

    private static final String JAVA_ARRAY_INTEGER = "int[]";
    private static final String JAVA_ARRAY_BYTE = "byte[]";
    private static final String JAVA_ARRAY_SHORT = "short[]";
    private static final String JAVA_ARRAY_LONG = "long[]";
    private static final String JAVA_ARRAY_FLOAT = "float[]";
    private static final String JAVA_ARRAY_DOUBLE = "double[]";
    private static final String JAVA_ARRAY_BOOLEAN = "boolean[]";
    private static final String JAVA_ARRAY_CHARACTER = "character[]";
    private static final String JAVA_ARRAY_SUFFIX = "[]";

    /**
     * ======================================java基本集合常量============================================================
     */
    private static final String JAVA_UTIL_MAP = "java.util.Map";
    private static final String JAVA_UTIL_HASH_MAP = "java.util.HashMap";
    private static final String JAVA_UTIL_TREE_MAP = "java.util.TreeMap";
    private static final String JAVA_UTIL_LIST = "java.util.List";
    private static final String JAVA_UTIL_ARRAY_LIST = "java.util.ArrayList";
    private static final String JAVA_UTIL_LINKED_LIST = "java.util.LinkedList";


    static {
        sBasicClass.add(JAVA_LANG_INTEGER);
        sBasicClass.add(JAVA_LANG_STRING);
        sBasicClass.add(JAVA_LANG_SHORT);
        sBasicClass.add(JAVA_LANG_BYTE);
        sBasicClass.add(JAVA_LANG_LONG);
        sBasicClass.add(JAVA_LANG_DOUBLE);
        sBasicClass.add(JAVA_LANG_CHARACTER);
        sBasicClass.add(JAVA_LANG_BOOLEAN);
        sBasicClass.add(JAVA_INTEGER);
        sBasicClass.add(JAVA_SHORT);
        sBasicClass.add(JAVA_BYTE);
        sBasicClass.add(JAVA_LONG);
        sBasicClass.add(JAVA_FLOAT);
        sBasicClass.add(JAVA_DOUBLE);
        sBasicClass.add(JAVA_BOOLEAN);
        sBasicClass.add(JAVA_CHARACTER);
    }


    /**
     * 格式化json字符串
     */
    private static String formatJsonStringInner(String json) {
        if (json == null || json.isEmpty()) {
            return EMPTY;
        }

        StringBuilder sb = new StringBuilder();
        char[] chars = json.toCharArray();
        int count = 0;
        final int basic = 4;
        char empty = ' ';
        boolean needEmpty = false;
        for (char aChar : chars) {

            if (aChar == LEFT || aChar == ARRAY_LEFT) {
                count++;
                sb.append(aChar);
                sb.append('\n');
                needEmpty = true;
            }

            if (aChar == POINT) {
                sb.append(POINT);
                sb.append('\n');
                needEmpty = true;
            }

            if (aChar == RIGHT || aChar == ARRAY_RIGHT) {
                sb.append('\n');
                count--;
                needEmpty = true;
            }

            //填充空白
            if (needEmpty) {
                sb.append(String.valueOf(empty).repeat(Math.max(0, count * basic)));
                if (aChar == RIGHT || aChar == ARRAY_RIGHT) {
                    sb.append(aChar);
                }
                needEmpty = false;
                continue;
            }
            sb.append(aChar);
        }
        return sb.toString();
    }


    private static <T> T fromJsonInner(String json, Class<T> clazz) {
        //1,json解析成map
        Map<String, String> map1 = transToMap(json);

        //2，遍历 class field，从中取出map
        Map<String, Object> map2 = parseMap(clazz, map1);

        //3,实例化class，赋值map中数据
        return performInstance(clazz, map2);
    }

    /**
     * 依赖默认构造方法
     */
    @SuppressWarnings("all")
    private static <T> T performInstance(Class<T> clazz, Map<String, Object> map) {
        T t = validInstance(clazz);
        try {
            for (String fieldName : map.keySet()) {
                Field field = tryFindField(clazz, fieldName);
                field.set(t, map.get(fieldName));
            }
        } catch (Exception e) {
            ignore(e);
        }

        return t;
    }

    private static <T> Field tryFindField(Class<T> clazz, String fieldName) throws NoSuchFieldException {
        Class<?> tempClass = clazz;

        while (tempClass != null && !tempClass.equals(Object.class)) {

            try {
                Field field = tempClass.getDeclaredField(fieldName);
                field.setAccessible(true);
                return field;
            } catch (NoSuchFieldException e) {
                tempClass = tempClass.getSuperclass();
            }
        }

        throw new NoSuchFieldException();
    }

    @SuppressWarnings("unchecked")
    private static <T> T validInstance(Class<T> clazz) {
        T t = null;
        Constructor<?>[] constructors = clazz.getConstructors();
        if (constructors.length == 0) {
            throw new IllegalArgumentException("can't invoke instance for " + clazz + " ,no declared constructor with modify is public");
        }

        for (Constructor<?> constructor : constructors) {
            Object[] params = genericEmptyConstructorParams(constructor);
            try {
                t = (T) constructor.newInstance(params);
                break;
            } catch (Exception e) {
                ignore(e);
            }
        }

        if (t == null) {
            throw new RuntimeException("can't invoke instance for " + clazz);
        }
        return t;
    }

    private static Object[] genericEmptyConstructorParams(Constructor<?> constructor) {
        Object[] params = new Object[constructor.getParameterCount()];

        Class<?>[] parameterTypes = constructor.getParameterTypes();

        for (int i = 0; i < parameterTypes.length; i++) {
            if (isBasicType(parameterTypes[i])) {
                if (parameterTypes[i].getName().equals(JAVA_LANG_BOOLEAN)) {
                    params[i] = basicValueOf("false", parameterTypes[i]);
                } else {
                    params[i] = basicValueOf("0", parameterTypes[i]);
                }
            } else {
                params[i] = null;
            }
        }
        return params;
    }

    private static Map<String, Object> parseMap(Class<?> clazz, Map<String, String> map) {

        Map<String, Object> objectMap = new HashMap<>();

        Class<?> tempClass = clazz;
        while (tempClass != null && !tempClass.equals(Object.class)) {

            objectMap.putAll(readObject(tempClass, map));

            tempClass = tempClass.getSuperclass();
        }


        return objectMap;
    }

    private static Map<String, Object> readObject(Class<?> clazz, Map<String, String> map) {
        Map<String, Object> map2 = new HashMap<>();

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String value = map.get(field.getName());
            if (value == null || value.isEmpty()) {
                continue;
            }

            Object obj = null;
            Type type = field.getGenericType();
            if (isArrayOrList(value)) {

                Class<?> parentClass = null;

                //数组或者集合 类型
                String className = genericClassNameForArray(type.getTypeName());
                if (isList(className)) {
                    //list类现
                    int subTypeIndex = className.indexOf(TYPE_LEFT);
                    String parentType = className.substring(0, subTypeIndex);
                    String subType = className.substring(subTypeIndex + 1, className.length() - 1);
                    Class<?> subClass = null;

                    try {
                        parentClass = Class.forName(parentType);
                        if (!subType.isEmpty()) {
                            subClass = Class.forName(subType);
                        }
                    } catch (ClassNotFoundException e) {
                        ignore(e);
                    }
                    if (parentClass == null || subClass == null) {
                        throw new RuntimeException("failed! parseMap : parentClass == null || subClass == null");
                    }
                    obj = parseList(value, parentClass, subClass);
                } else {
                    //数组不支持协变
                    try {
                        parentClass = Class.forName(className);
                    } catch (ClassNotFoundException e) {
                        ignore(e);
                    }
                    if (parentClass == null) {
                        throw new RuntimeException("failed!");
                    }
                    obj = parseArrayObject(value, parentClass);
                }
            } else if (isBasicType(type)) {
                obj = basicValueOf(value, type.getTypeName());
            } else if (isMap(type.getTypeName())) {
                //Map类型
                String className = genericClassNameForMap(type.getTypeName());
                int p1 = type.getTypeName().indexOf(TYPE_LEFT);
                int p2 = type.getTypeName().indexOf(POINT);
                int p3 = type.getTypeName().indexOf(TYPE_RIGHT);
                String type1 = type.getTypeName().substring(p1 + 1, p2);
                String type2 = type.getTypeName().substring(p2 + 2, p3);
                try {
                    Class<?> mapClass = Class.forName(className);
                    Class<?> type1Class = Class.forName(type1);
                    Class<?> type2Class = Class.forName(type2);

                    obj = parseMapObject(value, mapClass, type1Class, type2Class);
                } catch (ClassNotFoundException e) {
                    ignore(e);
                }
            } else {
                try {
                    obj = fromJsonInner(value, Class.forName(type.getTypeName()));
                } catch (ClassNotFoundException e) {
                    ignore(e);
                }
            }

            map2.put(field.getName(), obj);
        }
        return map2;
    }

    private static boolean isArrayOrList(String value) {
        return !value.isEmpty() && value.charAt(0) == ARRAY_LEFT;
    }

    private static boolean isBasicType(Type type) {
        if (type == null) {
            return false;
        }
        return sBasicClass.contains(type.getTypeName());
    }

    @SuppressWarnings("all")
    private static <K, V> Map<K, V> parseMapObject(String value, Class<?> mapClass, Class<K> keyClass, Class<V> valueClass) {

        assertStringNotNullOrEmpty(value);

        Map<K, V> map = new HashMap<>();

        Map<String, String> stringMap = transToMap(value);

        for (Map.Entry<String, String> entry : stringMap.entrySet()) {
            K k;
            V v;

            if (isBasicType(keyClass)) {
                k = (K) basicValueOf(entry.getKey(), keyClass);
            } else {
                k = (K) fromJsonInner(entry.getKey(), keyClass);
            }

            if (isBasicType(valueClass)) {
                v = (V) basicValueOf(entry.getValue(), valueClass);
            } else {
                v = (V) fromJsonInner(entry.getValue(), valueClass);
            }

            map.put(k, v);
        }

        return map;
    }

    private static String genericClassNameForMap(String typeName) {

        assertStringNotNullOrEmpty(typeName);

        //in current , only return hashMap
        return JAVA_UTIL_HASH_MAP;
    }

    private static boolean isMap(String typeName) {

        assertStringNotNullOrEmpty(typeName);

        return typeName.startsWith(JAVA_UTIL_MAP) || typeName.startsWith(JAVA_UTIL_HASH_MAP) || typeName.startsWith(JAVA_UTIL_TREE_MAP);
    }

    private static void ignore(Throwable e) {
        //ignore
    }

    @SuppressWarnings("all")
    private static <T> List<T> parseList(String data, Class<?> parentClass, Class<T> subClass) {

        assertStringNotNullOrEmpty(data);

        List<String> dataList = transToList(data);

        List<T> list = new ArrayList<>();

        if (isBasicType(subClass)) {
            for (String value : dataList) {
                list.add((T) basicValueOf(value, subClass));
            }
        } else {
            for (String value : dataList) {
                list.add(fromJsonInner(value, subClass));
            }
        }

        return list;
    }

    private static boolean isList(String s) {
        return s.startsWith(JAVA_UTIL_LIST) || s.startsWith(JAVA_UTIL_ARRAY_LIST) || s.startsWith(JAVA_UTIL_LINKED_LIST);
    }

    private static String genericClassNameForArray(String typeName) {

        assertStringNotNullOrEmpty(typeName);

        String className = typeName;
        if (typeName.startsWith("[L")) {
            //such as [Ljava.lang.String;
            className = typeName.substring(2);
        } else {
            switch (typeName) {
                case JAVA_ARRAY_INTEGER:
                    className = JAVA_LANG_INTEGER;
                    break;
                case JAVA_ARRAY_BYTE:
                    className = JAVA_LANG_BYTE;
                    break;
                case JAVA_ARRAY_SHORT:
                    className = JAVA_LANG_SHORT;
                    break;
                case JAVA_ARRAY_LONG:
                    className = JAVA_LANG_LONG;
                    break;
                case JAVA_ARRAY_DOUBLE:
                    className = JAVA_LANG_DOUBLE;
                    break;
                case JAVA_ARRAY_FLOAT:
                    className = JAVA_LANG_FLOAT;
                    break;
                case JAVA_ARRAY_BOOLEAN:
                    className = JAVA_LANG_BOOLEAN;
                    break;
                case JAVA_ARRAY_CHARACTER:
                    className = JAVA_LANG_CHARACTER;
                    break;
                default:
                    //for object
                    if (typeName.endsWith(JAVA_ARRAY_SUFFIX)) {
                        className = typeName.substring(0, typeName.length() - 2);
                    }
            }
        }
        return className;
    }

    @SuppressWarnings("unchecked")
    private static <T> T[] parseArrayObject(String s, Class<T> clazz) {

        assertStringNotNullOrEmpty(s);

        List<String> list = transToList(s);

        List<T> target = new ArrayList<>();

        if (isBasicType(clazz)) {
            for (String value : list) {
                target.add((T) basicValueOf(value, clazz));
            }
        } else {

            for (String value : list) {
                target.add(fromJsonInner(value, clazz));
            }
        }

        T[] arr = (T[]) Array.newInstance(clazz, target.size());

        for (int i = 0; i < arr.length; i++) {
            arr[i] = target.get(i);
        }
        return arr;
    }

    private static Object basicValueOf(String value, Class<?> className) {
        return basicValueOf(value, className.getName());
    }

    private static Object basicValueOf(String value, @BasicType String className) {
        Object obj = null;

        switch (className) {
            case JAVA_INTEGER:
            case JAVA_LANG_INTEGER:
                obj = Integer.valueOf(value);
                break;
            case JAVA_LONG:
            case JAVA_LANG_LONG:
                obj = Long.valueOf(value);
                break;
            case JAVA_BYTE:
            case JAVA_LANG_BYTE:
                obj = Byte.valueOf(value);
                break;
            case JAVA_BOOLEAN:
            case JAVA_LANG_BOOLEAN:
                obj = Boolean.valueOf(value);
                break;
            case JAVA_SHORT:
            case JAVA_LANG_SHORT:
                obj = Short.valueOf(value);
                break;
            case JAVA_LANG_STRING:
                obj = value;
                break;
            case JAVA_CHARACTER:
            case JAVA_LANG_CHARACTER:
                obj = value.toCharArray()[0];
                break;
            case JAVA_DOUBLE:
            case JAVA_LANG_DOUBLE:
                obj = Double.valueOf(value);
                break;
            case JAVA_FLOAT:
            case JAVA_LANG_FLOAT:
                obj = Float.valueOf(value);
                break;
        }
        return obj;
    }

    private static List<String> transToList(String s) {

        assertStringNotNullOrEmpty(s);

        List<String> list = new ArrayList<>();

        char[] chars = s.toCharArray();

        int p = 0;
        int start = 1;
        int end = s.length() - 1;
        Stack<Character> stack = new Stack<>();
        boolean ex = false;

        for (int i = start; i < end; i++) {
            if (chars[i] == LEFT) {
                stack.push(chars[i]);
                p = i;
                ex = true;
                continue;
            } else if (stack.isEmpty() && (chars[i - 1] == POINT || chars[i - 1] == ARRAY_LEFT || chars[i - 1] == LEFT)) {
                p = ex ? i - 1 : i;
            }

            if (!stack.isEmpty() && matchStack(chars[i], stack.peek())) {
                stack.pop();
            }
            if (stack.isEmpty() && (chars[i + 1] == POINT || chars[i + 1] == ARRAY_RIGHT)) {
                String value = new String(chars, p, i - p + 1);
                list.add(adjustValue(value));
                ex = false;
            }
        }

        return list;
    }

    /**
     * 符号匹配
     */
    private static Map<String, String> transToMap(String json) {
        assertStringNotNullOrEmpty(json);

        Map<String, String> cacheMap = new HashMap<>();

        int pl = 0;
        int pr = 0;

        //ignore first and last
        int start = 1;
        int end = json.length() - 1;

        char[] chars = json.toCharArray();
        Stack<Character> stack = new Stack<>();

        for (int i = start; i < end; ) {

            //find key
            for (; i < end; i++) {

                if (i == start || chars[i - 1] == POINT || chars[i - 1] == LEFT) {
                    //consider “/“” for every key
                    pl = i + 1;
                    continue;
                }

                if (i + 1 < end && chars[i + 1] == MAO_POINT) {
                    pr = i;
                    break;
                }
            }

            String key = new String(chars, pl, pr - pl);

            //find value
            i += 2;
            if (i < end) {
                pl = i;
            } else {
                break;
            }

            for (; i < end; i++) {
                if (chars[i] == LEFT || chars[i] == ARRAY_LEFT) {
                    stack.push(chars[i]);
                    continue;
                }

                if (!stack.isEmpty()) {
                    if (matchStack(chars[i], stack.peek())) {
                        stack.pop();
                    }
                }

                if (stack.isEmpty() && (chars[i + 1] == POINT || chars[i + 1] == RIGHT)) {
                    pr = i + 1;
                    break;
                }
            }

            String value = new String(chars, pl, pr - pl);
            cacheMap.put(key, adjustValue(value));
        }

        if (!stack.isEmpty()) {
            throw new RuntimeException("invalid json string!");
        }

        return cacheMap;
    }


    /**
     * 调整引号
     */
    private static String adjustValue(String value) {
        if (value.startsWith("\"") && value.endsWith("\"") && value.length() >= 2) {
            return adjustValue(value.substring(1, value.length() - 1));
        }
        return value;
    }

    private static boolean matchStack(char c, Character top) {
        return (c == RIGHT && top == LEFT) || (c == ARRAY_RIGHT && top == ARRAY_LEFT);
    }

    private static String toJsonInner(Object obj) {
        if (obj == null) {
            return EMPTY;
        }
        if (isArray(obj)) {
            return forArray(obj);
        }
        if (isIteratorForObject(obj)) {
            return forIterator((Iterable<?>) obj);
        }

        if (isMapForObject(obj)) {
            return forMap((Map<?, ?>) obj);
        }

        return forObject(obj);
    }

    private static String forObject(Object obj) {
        StringBuilder sb = new StringBuilder();

        sb.append(LEFT);


        sb.append(writeObject(obj, obj.getClass()));

        Class<?> superClass = obj.getClass().getSuperclass();
        while (superClass != null && !superClass.equals(Object.class)) {

            sb.append(POINT);

            sb.append(writeObject(obj, superClass));

            superClass = superClass.getSuperclass();
        }


        sb.append(RIGHT);
        return sb.toString();
    }

    private static String writeObject(Object obj, Class<?> clazz) {

        if (!clazz.isInstance(obj)) {
            return EMPTY;
        }

        StringBuilder sb = new StringBuilder();

        try {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                Object o = field.get(obj);
                sb.append("\"").append(field.getName()).append("\"");
                sb.append(":");
                //写值
                if (o instanceof Number) {
                    if (o instanceof Double || o instanceof Float) {
                        sb.append(((Number) o).doubleValue());
                    } else {
                        sb.append(((Number) o).longValue());
                    }
                } else if (o instanceof Boolean) {
                    sb.append(((Boolean) o).booleanValue());
                } else if (o instanceof CharSequence) {
                    sb.append('\"').append(((CharSequence) o)).append('\"');
                } else {
                    sb.append(toJsonInner(o));
                }
                sb.append(",");
            }

            //删除最后一个 ，
            if (sb.charAt(sb.length() - 1) == POINT) {
                sb.deleteCharAt(sb.length() - 1);
            }
        } catch (Exception e) {
            ignore(e);
        }

        return sb.toString();
    }


    private static String unFormatJsonStringInner(String json) {
        assertStringNotNullOrEmpty(json);

        StringBuilder sb = new StringBuilder();

        char[] chars = json.toCharArray();

        for (char c : chars) {
            if (c == ' ' || c == '\n') {
                continue;
            }

            sb.append(c);
        }
        return sb.toString();
    }


    private static String forMap(Map<?, ?> obj) {

        StringBuilder sb = new StringBuilder();
        sb.append(LEFT);

        for (Map.Entry<?, ?> entry : obj.entrySet()) {
            Object value = entry.getValue();
            sb.append('\"').append(entry.getKey()).append('\"').append(MAO_POINT);
            if (value instanceof CharSequence) {
                sb.append('\"').append(entry.getValue()).append('\"').append(POINT);
            } else {
                sb.append(entry.getValue()).append(POINT);
            }
        }


        if (sb.length() > 0 && sb.charAt(sb.length() - 1) == POINT) {
            sb.deleteCharAt(sb.length() - 1);
        }
        sb.append(RIGHT);
        return sb.toString();
    }

    private static boolean isMapForObject(Object obj) {
        return obj instanceof Map;
    }

    private static boolean isIteratorForObject(Object obj) {
        return obj instanceof Iterable;
    }

    private static String forIterator(Iterable<?> obj) {

        StringBuilder sb = new StringBuilder();
        sb.append(ARRAY_LEFT);

        Iterator<?> iterator = obj.iterator();
        Object tempObj;
        while (iterator.hasNext()) {
            Object next = iterator.next();
            sb.append(sBasicClass.contains(next.getClass().getName()) ? ((tempObj = basicValueOf(next.toString(), next.getClass())) instanceof String ? "\"" + tempObj + "\"" : tempObj) : toJsonInner(next));
            sb.append(POINT);
        }

        if (sb.length() > 0 && sb.charAt(sb.length() - 1) == POINT) {
            sb.deleteCharAt(sb.length() - 1);
        }
        sb.append(ARRAY_RIGHT);
        return sb.toString();
    }

    private static String forArray(Object obj) {
        StringBuilder sb = new StringBuilder();
        sb.append(ARRAY_LEFT);
        if (obj instanceof byte[]) {
            for (int i = 0; i < ((byte[]) obj).length; i++) {
                sb.append(((byte[]) obj)[i]);
                sb.append(POINT);
            }
        } else if (obj instanceof short[]) {
            for (int i = 0; i < ((short[]) obj).length; i++) {
                sb.append(((short[]) obj)[i]);
                sb.append(POINT);
            }
        } else if (obj instanceof char[]) {
            for (int i = 0; i < ((char[]) obj).length; i++) {
                sb.append(((char[]) obj)[i]);
                sb.append(POINT);
            }
        } else if (obj instanceof int[]) {
            for (int i = 0; i < ((int[]) obj).length; i++) {
                sb.append(((int[]) obj)[i]);
                sb.append(POINT);
            }
        } else if (obj instanceof long[]) {
            for (int i = 0; i < ((long[]) obj).length; i++) {
                sb.append(((long[]) obj)[i]);
                sb.append(POINT);
            }
        } else if (obj instanceof float[]) {
            for (int i = 0; i < ((float[]) obj).length; i++) {
                sb.append(((float[]) obj)[i]);
                sb.append(POINT);
            }
        } else if (obj instanceof double[]) {
            for (int i = 0; i < ((double[]) obj).length; i++) {
                sb.append(((double[]) obj)[i]);
                sb.append(POINT);
            }
        } else if (obj instanceof boolean[]) {
            for (int i = 0; i < ((boolean[]) obj).length; i++) {
                sb.append(((boolean[]) obj)[i]);
                sb.append(POINT);
            }
        } else if (obj instanceof Integer[]) {
            for (int i = 0; i < ((Integer[]) obj).length; i++) {
                sb.append(((Integer[]) obj)[i].intValue());
                sb.append(POINT);
            }
        } else if (obj instanceof Byte[]) {
            for (int i = 0; i < ((Byte[]) obj).length; i++) {
                sb.append(((Byte[]) obj)[i].byteValue());
                sb.append(POINT);
            }
        } else if (obj instanceof Character[]) {
            for (int i = 0; i < ((Character[]) obj).length; i++) {
                sb.append(((Character[]) obj)[i].charValue());
                sb.append(POINT);
            }
        } else if (obj instanceof Short[]) {
            for (int i = 0; i < ((Short[]) obj).length; i++) {
                sb.append(((Short[]) obj)[i].shortValue());
                sb.append(POINT);
            }
        } else if (obj instanceof Double[]) {
            for (int i = 0; i < ((Double[]) obj).length; i++) {
                sb.append(((Double[]) obj)[i].doubleValue());
                sb.append(POINT);
            }
        } else if (obj instanceof Float[]) {
            for (int i = 0; i < ((Float[]) obj).length; i++) {
                sb.append(((Float[]) obj)[i].floatValue());
                sb.append(POINT);
            }
        } else if (obj instanceof Boolean[]) {
            for (int i = 0; i < ((Boolean[]) obj).length; i++) {
                sb.append(((Boolean[]) obj)[i].booleanValue());
                sb.append(POINT);
            }
        } else if (obj instanceof String[]) {
            for (int i = 0; i < ((String[]) obj).length; i++) {
                sb.append(((String[]) obj)[i]);
                sb.append(POINT);
            }
        } else {
            Object[] objects = (Object[]) obj;
            for (Object object : objects) {
                sb.append(toJsonInner(object));
                sb.append(POINT);
            }
        }

        if (sb.length() > 0 && sb.charAt(sb.length() - 1) == POINT) {
            sb.deleteCharAt(sb.length() - 1);
        }

        sb.append(ARRAY_RIGHT);
        return sb.toString();
    }

    private static boolean isArray(Object obj) {
        return (obj instanceof byte[]) || (obj instanceof short[]) || (obj instanceof char[]) || (obj instanceof int[]) || (obj instanceof long[]) || (obj instanceof float[]) || (obj instanceof double[]) || (obj instanceof boolean[]) || (obj instanceof Object[]);
    }


    private static void assertStringNotNullOrEmpty(String json) {
        if (json == null || json.isEmpty()) {
            throw new RuntimeException("try to parse empty string to json");
        }
    }


    @Retention(RetentionPolicy.SOURCE)
    @Target(value = ElementType.PARAMETER)
    public @interface BasicType {
        String STRING = JsonUtils.JAVA_LANG_STRING;
        String INTEGER = JsonUtils.JAVA_LANG_INTEGER;
        String BYTE = JsonUtils.JAVA_LANG_BYTE;
        String SHORT = JsonUtils.JAVA_LANG_SHORT;
        String LONG = JsonUtils.JAVA_LANG_LONG;
        String FLOAT = JsonUtils.JAVA_LANG_FLOAT;
        String DOUBLE = JsonUtils.JAVA_LANG_DOUBLE;
        String BOOLEAN = JsonUtils.JAVA_LANG_BOOLEAN;
        String CHARACTER = JsonUtils.JAVA_LANG_CHARACTER;
    }
}
